import os
import time
import re
import io
import threading
import json

import random
import traceback

from common.mysql.MySQLhelper import MySQLhelper
from common.mysql.shequn_accept_message_info import get_accept_user_info, update_accept_user_list, \
    delete_accept_message_info_by_user_id
from common.mysql.shequn_assign_person import insert_assign_person_base_value, delete_assign_person_by_user_id
from common.mysql.shequn_key_word_find import get_key_word_find, update_key_word_list
from common.mysql.shequn_message_catch import delete_shequn_message_catch_by_user_id
from common.mysql.shequn_top_user import delete_top_user_by_user_id
from common.user_data_util import *
from common.mysql.shequn_user_mysql import *
from common.mysql.shequn_user_tag_mysql import *
from common.mysql.shequn_friend_tag_mysql import *
from common.mysql.shequn_service_manager_mysql import *
from common.mysql.shequn_qr_code_mysql import *
from ... import itchat

try:
    from httplib import BadStatusLine
except ImportError:
    from http.client import BadStatusLine

import requests
from pyqrcode import QRCode

from .. import config, utils
from ..returnvalues import ReturnValue
from ..storage.templates import wrap_user_dict
from .contact import update_local_chatrooms, update_local_friends
from .messages import produce_msg

logger = logging.getLogger('itchat')
import shortuuid

sqlhelper = get_sql_helper()


def load_login(core):
    core.login = login
    core.get_QRuuid = get_QRuuid
    core.get_QR = get_QR
    core.check_login = check_login
    core.web_init = web_init
    core.show_mobile_login = show_mobile_login
    core.start_receiving = start_receiving
    core.get_msg = get_msg
    core.logout = logout


def login(self, enableCmdQR=False, picDir=None, qrCallback=None,
          loginCallback=None, exitCallback=None):
    if self.alive or self.isLogging:
        logger.warning('itchat has already logged in.')
        return
    self.isLogging = True
    logger.info('Ready to login.')
    while self.isLogging:
        uuid = push_login(self)
        if uuid:
            qrStorage = io.BytesIO()
        else:
            logger.info('Getting uuid of QR code.')
            while not self.get_QRuuid():
                time.sleep(1)
            logger.info('Downloading QR code.')
            qrStorage = self.get_QR(enableCmdQR=enableCmdQR,
                                    picDir=picDir, qrCallback=qrCallback)
            # logger.info('Please scan the QR code to log in.')
        isLoggedIn = False
        while not isLoggedIn:
            status = self.check_login()
            if hasattr(qrCallback, '__call__'):
                qrCallback(uuid=self.uuid, status=status,
                           qrcode=qrStorage.getvalue())
            if status == '200':
                isLoggedIn = True
            elif status == '201':
                if isLoggedIn is not None:
                    logger.info('Please press confirm on your phone.')
                    isLoggedIn = None
                    time.sleep(7)
                time.sleep(0.5)
            elif status != '408':
                break
        if isLoggedIn:
            break
        elif self.isLogging:
            logger.info('Log in time out, reloading QR code.')
    else:
        return  # log in process is stopped by user
    logger.info('Loading the contact, this may take a little while.')
    self.web_init()
    self.show_mobile_login()
    self.get_contact(True)
    if hasattr(loginCallback, '__call__'):
        r = loginCallback()
    else:
        # utils.clear_screen()
        if os.path.exists(picDir or config.DEFAULT_QR):
            os.remove(picDir or config.DEFAULT_QR)
        logger.info('Login successfully as %s' % self.storageClass.nickName)
    self.start_receiving(exitCallback)
    logger.info('Loading the contact, this may take a little while.')
    login_fix(self)
    self.isLogging = False


# 将用户好友的数据注入到数据库中
def insert_friend_data(member_list, nick_name, user_id, today, mul_ori, wechat_map):
    update_wechat_data = []
    insert_wechat_data = []
    for index in member_list:
        # seq个人好友的唯一标识
        seq = get_seq(index)
        # 找到了个人好友
        if wechat_map.get(seq) != None:
            # 修改数据
            # nick_name当前用户，user_id当前用户， index当前好友的数据， seq个人好友的唯一标识
            # 需要修改朋友的信息为新的信息
            insert_data = [nick_name, user_id, index.NickName, index.UserName, index.RemarkName, today, seq]
            update_wechat_data.append(insert_data)
            # update_wechat_user(nick_name, user_id, index, today, seq)
            del wechat_map[seq]
        else:
            # 数据不存在，可能是新增的用户，或者是自己
            insert_data = [str(shortuuid.ShortUUID().random(20)), today, today, nick_name, user_id, index.NickName,
                           index.UserName, index.Province, index.City, index.RemarkName, False, seq, mul_ori]
            insert_wechat_data.append(insert_data)
            insert_wechat_user(index, today, nick_name, user_id, seq, mul_ori)
    update_wechat_user_list(update_wechat_data)
    insert_wechat_user_list(insert_wechat_data)


# 将用户的群聊注入到数据库中
def insert_user_group(chat_room_list, today, nick_name, user_id, wechat_map):
    for index in chat_room_list:
        mul_value_low, mul_value_top, room_mul_ori = mul_attr_status(index.MemberList)
        if room_mul_ori == 0:
            room_mul_ori = generate_unique_id()
            insert_wechat_user_room(index, today, nick_name, user_id, room_mul_ori)
            continue
        flag = False
        for key, value in wechat_map.items():
            key_num = int(key)
            if key_num >= mul_value_low and key_num <= mul_value_top:
                # 说明是同一个群,找到群了
                update_wechat_user(nick_name, user_id, index, today, room_mul_ori)
                del wechat_map[key]
                flag = True
                break
        if flag == False:
            # 没有找到这个群，说明是新的群
            insert_wechat_user_room(index, today, nick_name, user_id, room_mul_ori)


def delete_value_in_wechat_map(wechat_map):
    for key, value in wechat_map.items():
        delete_wechat_user(value[0])


def insert_user_group_all(chat_room_list, today, nick_name, user_id):
    for index in chat_room_list:
        mul_value_low, mul_value_top, room_mul_ori = mul_attr_status(index.MemberList)
        if room_mul_ori == 0:
            room_mul_ori = generate_unique_id()
        insert_wechat_user_room(index, today, nick_name, user_id, room_mul_ori)


# 注入用户标签，默认需要将无标签和全部标签注入进来
def insert_user_tag(today, user_id):
    id01 = str(shortuuid.ShortUUID().random(20))
    id02 = str(shortuuid.ShortUUID().random(20))
    insert_user_tag_byId(id01, today, user_id, "1")
    insert_user_tag_byId(id02, today, user_id, "2")


# 通过老的用户id，查询到所有的数据，然后将新的数据注入进去，如果没有找到，那么将这个数据删除掉，说明这个数据已经不需要了
def update_old_friend_tag(old_user_id, old_map, today, user_id):
    friend_tag_data = get_friend_tag(old_user_id)
    if friend_tag_data != ():
        for index in friend_tag_data:
            old_friend_id = index[2]
            new_friend_value = old_map.get(old_friend_id)
            if new_friend_value != None:
                # 说明有数据，那么进行修改
                new_friend_id = new_friend_value.UserName
                update_friend_tag(today, new_friend_id, user_id, old_friend_id)
            else:
                # 进行删除
                # 获取到的数据都是新的数据，如果某个朋友不存在了，那么将数据删除掉
                delete_friend_tag(old_friend_id)


def update_old_value(user_id, today, wechat_user_value, old_map):
    old_user_id = get_update_old_value_need_data(wechat_user_value)
    # 将用户-标签替换掉
    update_old_tag_data(today, user_id, old_user_id)
    # 将用户-朋友-标签替换掉
    update_old_friend_tag(old_user_id, old_map, today, user_id)


def get_update_old_value_need_data(wechat_user_value):
    old_wechat_value = wechat_user_value[0]
    old_user_id = old_wechat_value[4]
    return old_user_id


def insert_assign_person(today, user_id, nick_name):
    id01 = str(shortuuid.ShortUUID().random(20))
    insert_assign_person_base_value(today, id01, user_id, nick_name)

def login_fix(self):
    user_id, today, nick_name, member_list, chat_room_list = get_need_param(self)
    # 求和算法
    # mul_value_low, mul_value_top, mul_ori = mul_value(member_list, nick_name)
    # 获取到之前的所有用户数据
    # wechat_user_old_value = get_wechat_user(mul_value_top, mul_value_low)
    # 将刚用户的新朋友信息，通过seq为key，数据为value进行组装
    # new_seq_map = build_new_seq_map(member_list)
    # if wechat_user_old_value != ():
    # 将用户信息，以seq为key，以朋友信息为value,组装为map
    # wechat_old_map = get_wechat_map(wechat_user_old_value)
    # old_map = build_old_data_for_key(new_seq_map, wechat_old_map)
    # # 将新数据注入到数据库中
    # ## 之后需要修改逻辑，现在不修改。群组的都需要进行删除，只保留新的群组
    # # 修改朋友的信息：1.查看朋友是否还在，不在就进行删除2.如果存在，就修改信息
    # insert_friend_data(member_list, nick_name, user_id, today, mul_ori, wechat_old_map)
    # insert_user_group(chat_room_list, today, nick_name, user_id, mul_ori, wechat_old_map)
    # # 查看map中是否还有数据，如果还有，进行删除
    # delete_value_in_wechat_map(wechat_old_map)
    # # 用户不是第一次登录，修改所有的数据为新的数据，这里写所有的数据替换逻辑。可以把前面的数据替换也放入其中
    # update_old_value(user_id, today, wechat_user_old_value, old_map)
    # else:
    # 没有找到数据，用户是第一次登录我们平台，会添加所有的好友到数据库
    insert_value(member_list, today, nick_name, user_id)
    insert_user_group_all(chat_room_list, today, nick_name, user_id)
    # 用户第一次登录，需要给用户增加两个标签
    insert_user_tag(today, user_id)
    insert_user_friend_tag(today, user_id, member_list)



    insert_service_manager(today, user_id, nick_name)
    insert_assign_person(today, user_id, nick_name)
    # 如果有相同的应用名，那么返回上一次登录的用户ID
    # old_apply_uuid = get_old_qr_data_by_apply_name(self.storageClass.nickName)
    update_qr_code(self, nick_name, user_id, today)
    # 如果上一次登录过，那么需要修改历史数据
    # if old_apply_uuid is not None:
    #     logger.info("修改历史数据。")
    #     update_old_data(old_apply_uuid, member_list, chat_room_list, user_id)


def update_accept_message_value_by_single(message, member, new_user_id):
    old_user_id = message.user_id
    msg_to_user_id = message.msg_to_user_id
    if old_user_id == msg_to_user_id:
        message.msg_from_user_id = member.UserName
        message.msg_to_user_id = new_user_id
    else:
        message.msg_from_user_id = new_user_id
        message.msg_to_user_id = member.UserName
    message.user_id = new_user_id
    message.msg_friend_id = member.UserName


def update_accept_message_info(message, friend_name_map, friend_group_name_map, user_id):
    # 根据用户ID和
    msg_is_group = message.msg_is_group
    nick_name = message.msg_friend_name
    if msg_is_group == None:
        return
    elif msg_is_group == 1:
        member = friend_group_name_map[nick_name]
    elif msg_is_group == 0:
        member = friend_name_map[nick_name]
    if (member == None):
        return
    update_accept_message_value_by_single(message, member, user_id)


def build_friend_name_map(member_list):
    friend_name_map = {}
    for index in member_list:
        name = index.NickName
        friend_name_map[name] = index
    return friend_name_map


def build_group_name_map(chat_room_list):
    group_name_map = {}
    for index in chat_room_list:
        name = index.NickName
        group_name_map[name] = index
    return group_name_map


def update_accept_message_data(old_apply_uuid, friend_name_map, friend_group_name_map, user_id):
    message_list = get_accept_user_info(old_apply_uuid)
    if message_list == []:
        return
    for message in message_list:
        update_accept_message_info(message, friend_name_map, friend_group_name_map, user_id)

    values = [(message.msg_from_user_id, message.msg_to_user_id, message.user_id, message.msg_friend_id, message.id) for
              message in
              message_list]
    update_accept_user_list(values)


def update_key_word_find_info(key_word, friend_name_map, friend_group_name_map, user_id):
    old_user_id = key_word.user_id
    from_user_name = key_word.from_user_name
    to_user_name = key_word.to_user_name
    if old_user_id == key_word.from_user_id:
        member = friend_name_map[to_user_name]
        if member == None:
            member = friend_group_name_map[to_user_name]
    else:
        member = friend_name_map[from_user_name]
        if member == None:
            member = friend_group_name_map[from_user_name]
    if member == None:
        return
    if old_user_id == key_word.from_user_id:
        key_word.from_user_id = user_id
        key_word.to_user_id = member.UserName
    else:
        key_word.to_user_id = user_id
        key_word.from_user_id = member.UserName
    key_word.user_id = user_id


def update_old_key_word_find(old_apply_uuid, friend_name_map, friend_group_name_map, user_id):
    key_word_find_list = get_key_word_find(old_apply_uuid)
    if key_word_find_list == None:
        return
    for key_word in key_word_find_list:
        update_key_word_find_info(key_word, friend_name_map, friend_group_name_map, user_id)
    values = [(key_word_find.from_user_id, key_word_find.to_user_id, key_word_find.user_id, key_word_find.id) for
              key_word_find in
              key_word_find_list]
    update_key_word_list(values)


def update_old_data(old_apply_uuid, member_list, chat_room_list, user_id):
    friend_name_map = build_friend_name_map(member_list)
    friend_group_name_map = build_group_name_map(chat_room_list)

    # 需要查看历史聊天记录，如果用户重新登录，那么userID会发生改变，需要进行重新修改
    update_accept_message_data(old_apply_uuid, friend_name_map, friend_group_name_map, user_id)
    update_old_key_word_find(old_apply_uuid, friend_name_map, friend_group_name_map, user_id)


def insert_service_manager(today, user_id, nick_name):
    id01 = str(shortuuid.ShortUUID().random(20))
    id02 = str(shortuuid.ShortUUID().random(20))
    insert_service_manager_by_value(id01, today, user_id, nick_name, 1, 1, '私聊管家')
    insert_service_manager_by_value(id02, today, user_id, nick_name, 2, 2, '群聊管家')


def insert_user_friend_tag(today, user_id, member_list):
    insert_friend_tag_data = []
    for index in member_list:
        if user_id == index.UserName:
            continue
        id01 = str(shortuuid.ShortUUID().random(20))
        id02 = str(shortuuid.ShortUUID().random(20))
        insert_data_01 = [id01, 'admin', today, 'admin', today, 1, user_id, index.UserName]
        insert_data_02 = [id02, 'admin', today, 'admin', today, 2, user_id, index.UserName]
        insert_friend_tag_data.append(insert_data_01)
        insert_friend_tag_data.append(insert_data_02)

    insert_friend_tag_list(insert_friend_tag_data)


# 组装一个map，将老的用户id作为key，新的数据作为map
def build_old_data_for_key(new_seq_map, wechat_old_map):
    old_friend_key_map = {}
    for key, value in new_seq_map.items():
        # 新的key在这里面找不到，直接跳过即可，用不到，可能是自己，也可能是新加的朋友，新加的朋友，如果没有找到，说明之前也没有加进来
        old_data = wechat_old_map.get(key)
        if old_data != None:
            old_key = old_data[6]
            old_friend_key_map[old_key] = value
    return old_friend_key_map


def get_need_param(self):
    user_id = itchat.instance.storageClass.userName
    nick_name = itchat.instance.storageClass.nickName
    member_list = self.memberList
    chat_room_list = self.chatroomList
    return user_id, get_today(), nick_name, member_list, chat_room_list


def insert_value(member_list, today, nick_name, user_id):
    insert_wechat_data = []
    for index in member_list:
        seq = get_seq(index)
        # 查找当前用户是否有历史记录
        # insert_wechat_user(index, today, nick_name, user_id, seq, mul_ori)
        insert_data = [str(shortuuid.ShortUUID().random(20)), today, today, nick_name, user_id, index.NickName,
                       index.UserName, index.Province, index.City, index.RemarkName, False, seq]
        insert_wechat_data.append(insert_data)
    insert_wechat_user_list(insert_wechat_data)


def update_qr_code(self, nick_name, user_id, today):
    # 如果应用名称已经存在，那么将上一个应用删除
    delete_qr_code_by_apply_name(self.storageClass.nickName)
    update_qr_code_apply_name(self.storageClass.nickName, MySQLhelper.container)
    update_qr_code_local(today, nick_name, user_id, self.uuid)


def insert_friend_tag(today, user_id, friend_id):
    if user_id == friend_id:
        return
    id01 = str(shortuuid.ShortUUID().random(20))
    id02 = str(shortuuid.ShortUUID().random(20))
    insert_friend_tag_by_tag_id(id01, today, user_id, friend_id, 1)
    insert_friend_tag_by_tag_id(id02, today, user_id, friend_id, 2)


def push_login(core):
    cookiesDict = core.s.cookies.get_dict()
    if 'wxuin' in cookiesDict:
        url = '%s/cgi-bin/mmwebwx-bin/webwxpushloginurl?uin=%s' % (
            config.BASE_URL, cookiesDict['wxuin'])
        headers = {'User-Agent': config.USER_AGENT}
        r = core.s.get(url, headers=headers).json()
        if 'uuid' in r and r.get('ret') in (0, '0'):
            core.uuid = r['uuid']
            return r['uuid']
    return False


def get_QRuuid(self):
    url = '%s/jslogin' % config.BASE_URL
    params = {
        'appid': 'wx782c26e4c19acffb',
        'fun': 'new',
        'redirect_uri': 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?mod=desktop',
        'lang': 'zh_CN'}
    headers = {'User-Agent': config.USER_AGENT}
    r = self.s.get(url, params=params, headers=headers)
    regx = r'window.QRLogin.code = (\d+); window.QRLogin.uuid = "(\S+?)";'
    data = re.search(regx, r.text)
    if data and data.group(1) == '200':
        self.uuid = data.group(2)
        return self.uuid


def get_QR(self, uuid=None, enableCmdQR=False, picDir=None, qrCallback=None):
    uuid = uuid or self.uuid
    picDir = picDir or config.DEFAULT_QR
    qrStorage = io.BytesIO()
    qrCode = QRCode('https://login.weixin.qq.com/l/' + uuid)
    qrCode.png(qrStorage, scale=10)
    if hasattr(qrCallback, '__call__'):
        qrCallback(uuid=uuid, status='0', qrcode=qrStorage.getvalue())
    else:
        with open(picDir, 'wb') as f:
            f.write(qrStorage.getvalue())
        if enableCmdQR:
            utils.print_cmd_qr(qrCode.text(1), enableCmdQR=enableCmdQR)
        else:
            utils.print_qr(picDir)
    return qrStorage


def check_login(self, uuid=None):
    uuid = uuid or self.uuid
    url = '%s/cgi-bin/mmwebwx-bin/login' % config.BASE_URL
    localTime = int(time.time())
    params = 'loginicon=true&uuid=%s&tip=1&r=%s&_=%s' % (
        uuid, int(-localTime / 1579), localTime)
    headers = {'User-Agent': config.USER_AGENT}
    r = self.s.get(url, params=params, headers=headers)
    regx = r'window.code=(\d+)'
    data = re.search(regx, r.text)
    if data and data.group(1) == '200':
        if process_login_info(self, r.text):
            return '200'
        else:
            return '400'
    elif data:
        return data.group(1)
    else:
        return '400'


def process_login_info(core, loginContent):
    ''' when finish login (scanning qrcode)
     * syncUrl and fileUploadingUrl will be fetched
     * deviceid and msgid will be generated
     * skey, wxsid, wxuin, pass_ticket will be fetched
    '''
    regx = r'window.redirect_uri="(\S+)";'
    core.loginInfo['url'] = re.search(regx, loginContent).group(1)
    headers = {'User-Agent': config.USER_AGENT,
               'client-version': config.UOS_PATCH_CLIENT_VERSION,
               'extspam': config.UOS_PATCH_EXTSPAM,
               'referer': 'https://wx.qq.com/?&lang=zh_CN&target=t'
               }
    r = core.s.get(core.loginInfo['url'],
                   headers=headers, allow_redirects=False)
    core.loginInfo['url'] = core.loginInfo['url'][:core.loginInfo['url'].rfind(
        '/')]
    for indexUrl, detailedUrl in (
            ("wx2.qq.com", ("file.wx2.qq.com", "webpush.wx2.qq.com")),
            ("wx8.qq.com", ("file.wx8.qq.com", "webpush.wx8.qq.com")),
            ("qq.com", ("file.wx.qq.com", "webpush.wx.qq.com")),
            ("web2.wechat.com", ("file.web2.wechat.com", "webpush.web2.wechat.com")),
            ("wechat.com", ("file.web.wechat.com", "webpush.web.wechat.com"))):
        fileUrl, syncUrl = ['https://%s/cgi-bin/mmwebwx-bin' %
                            url for url in detailedUrl]
        if indexUrl in core.loginInfo['url']:
            core.loginInfo['fileUrl'], core.loginInfo['syncUrl'] = \
                fileUrl, syncUrl
            break
    else:
        core.loginInfo['fileUrl'] = core.loginInfo['syncUrl'] = core.loginInfo['url']
    core.loginInfo['deviceid'] = 'e' + repr(random.random())[2:17]
    core.loginInfo['logintime'] = int(time.time() * 1e3)
    core.loginInfo['BaseRequest'] = {}
    cookies = core.s.cookies.get_dict()
    res = re.findall('<skey>(.*?)</skey>', r.text, re.S)
    skey = res[0] if res else None
    res = re.findall(
        '<pass_ticket>(.*?)</pass_ticket>', r.text, re.S)
    pass_ticket = res[0] if res else None
    if skey is not None:
        core.loginInfo['skey'] = core.loginInfo['BaseRequest']['Skey'] = skey
    core.loginInfo['wxsid'] = core.loginInfo['BaseRequest']['Sid'] = cookies["wxsid"]
    core.loginInfo['wxuin'] = core.loginInfo['BaseRequest']['Uin'] = cookies["wxuin"]
    if pass_ticket is not None:
        core.loginInfo['pass_ticket'] = pass_ticket
    # A question : why pass_ticket == DeviceID ?
    #               deviceID is only a randomly generated number

    # UOS PATCH By luvletter2333, Sun Feb 28 10:00 PM
    # for node in xml.dom.minidom.parseString(r.text).documentElement.childNodes:
    #     if node.nodeName == 'skey':
    #         core.loginInfo['skey'] = core.loginInfo['BaseRequest']['Skey'] = node.childNodes[0].data
    #     elif node.nodeName == 'wxsid':
    #         core.loginInfo['wxsid'] = core.loginInfo['BaseRequest']['Sid'] = node.childNodes[0].data
    #     elif node.nodeName == 'wxuin':
    #         core.loginInfo['wxuin'] = core.loginInfo['BaseRequest']['Uin'] = node.childNodes[0].data
    #     elif node.nodeName == 'pass_ticket':
    #         core.loginInfo['pass_ticket'] = core.loginInfo['BaseRequest']['DeviceID'] = node.childNodes[0].data
    if not all([key in core.loginInfo for key in ('skey', 'wxsid', 'wxuin', 'pass_ticket')]):
        logger.error(
            'Your wechat account may be LIMITED to log in WEB wechat, error info:\n%s' % r.text)
        core.isLogging = False
        return False
    return True


def web_init(self):
    url = '%s/webwxinit' % self.loginInfo['url']
    params = {
        'r': int(-time.time() / 1579),
        'pass_ticket': self.loginInfo['pass_ticket'], }
    data = {'BaseRequest': self.loginInfo['BaseRequest'], }
    headers = {
        'ContentType': 'application/json; charset=UTF-8',
        'User-Agent': config.USER_AGENT, }
    r = self.s.post(url, params=params, data=json.dumps(data), headers=headers)
    dic = json.loads(r.content.decode('utf-8', 'replace'))
    # deal with login info
    utils.emoji_formatter(dic['User'], 'NickName')
    self.loginInfo['InviteStartCount'] = int(dic['InviteStartCount'])
    self.loginInfo['User'] = wrap_user_dict(
        utils.struct_friend_info(dic['User']))
    self.memberList.append(self.loginInfo['User'])
    self.loginInfo['SyncKey'] = dic['SyncKey']
    self.loginInfo['synckey'] = '|'.join(['%s_%s' % (item['Key'], item['Val'])
                                          for item in dic['SyncKey']['List']])
    self.storageClass.userName = dic['User']['UserName']
    self.storageClass.nickName = dic['User']['NickName']
    # deal with contact list returned when init
    contactList = dic.get('ContactList', [])
    chatroomList, otherList = [], []
    for m in contactList:
        if m['Sex'] != 0:
            otherList.append(m)
        elif '@@' in m['UserName']:
            m['MemberList'] = []  # don't let dirty info pollute the list
            chatroomList.append(m)
        elif '@' in m['UserName']:
            # mp will be dealt in update_local_friends as well
            otherList.append(m)
    if chatroomList:
        update_local_chatrooms(self, chatroomList)
    if otherList:
        update_local_friends(self, otherList)
    return dic


def show_mobile_login(self):
    url = '%s/webwxstatusnotify?lang=zh_CN&pass_ticket=%s' % (
        self.loginInfo['url'], self.loginInfo['pass_ticket'])
    data = {
        'BaseRequest': self.loginInfo['BaseRequest'],
        'Code': 3,
        'FromUserName': self.storageClass.userName,
        'ToUserName': self.storageClass.userName,
        'ClientMsgId': int(time.time()), }
    headers = {
        'ContentType': 'application/json; charset=UTF-8',
        'User-Agent': config.USER_AGENT, }
    r = self.s.post(url, data=json.dumps(data), headers=headers)
    return ReturnValue(rawResponse=r)


def start_receiving(self, exitCallback=None, getReceivingFnOnly=False):
    self.alive = True

    def maintain_loop():
        retryCount = 0
        while self.alive:
            try:
                i = sync_check(self)
                if i is None:
                    self.alive = False
                elif i == '0':
                    pass
                else:
                    msgList, contactList = self.get_msg()
                    if msgList:
                        msgList = produce_msg(self, msgList)
                        for msg in msgList:
                            self.msgList.put(msg)
                    if contactList:
                        chatroomList, otherList = [], []
                        for contact in contactList:
                            if '@@' in contact['UserName']:
                                chatroomList.append(contact)
                            else:
                                otherList.append(contact)
                        chatroomMsg = update_local_chatrooms(
                            self, chatroomList)
                        chatroomMsg['User'] = self.loginInfo['User']
                        self.msgList.put(chatroomMsg)
                        update_local_friends(self, otherList)
                retryCount = 0
            except requests.exceptions.ReadTimeout:
                pass
            except:
                retryCount += 1
                logger.error(traceback.format_exc())
                if self.receivingRetryCount < retryCount:
                    logger.error("Having tried %s times, but still failed. " % (
                        retryCount) + "Stop trying...")
                    self.alive = False
                else:
                    time.sleep(1)
        self.logout()
        if hasattr(exitCallback, '__call__'):
            exitCallback()
        else:
            logger.info('LOG OUT!')

    if getReceivingFnOnly:
        return maintain_loop
    else:
        maintainThread = threading.Thread(target=maintain_loop)
        maintainThread.setDaemon(True)
        maintainThread.start()


def sync_check(self):
    url = '%s/synccheck' % self.loginInfo.get('syncUrl', self.loginInfo['url'])
    params = {
        'r': int(time.time() * 1000),
        'skey': self.loginInfo['skey'],
        'sid': self.loginInfo['wxsid'],
        'uin': self.loginInfo['wxuin'],
        'deviceid': self.loginInfo['deviceid'],
        'synckey': self.loginInfo['synckey'],
        '_': self.loginInfo['logintime'], }
    headers = {'User-Agent': config.USER_AGENT}
    self.loginInfo['logintime'] += 1
    try:
        r = self.s.get(url, params=params, headers=headers,
                       timeout=config.TIMEOUT)
    except requests.exceptions.ConnectionError as e:
        try:
            if not isinstance(e.args[0].args[1], BadStatusLine):
                raise
            # will return a package with status '0 -'
            # and value like:
            # 6f:00:8a:9c:09:74:e4:d8:e0:14:bf:96:3a:56:a0:64:1b:a4:25:5d:12:f4:31:a5:30:f1:c6:48:5f:c3:75:6a:99:93
            # seems like status of typing, but before I make further achievement code will remain like this
            return '2'
        except:
            raise
    r.raise_for_status()
    regx = r'window.synccheck={retcode:"(\d+)",selector:"(\d+)"}'
    pm = re.search(regx, r.text)
    if pm is None or pm.group(1) != '0':
        user_id = itchat.instance.storageClass.userName
        # 后面增加更新时间
        update_qr_code_by_user_id(user_id)
        delete_accept_message_info_by_user_id(user_id)
        delete_shequn_message_catch_by_user_id(user_id)
        delete_service_manager(user_id)
        delete_top_user_by_user_id(user_id)
        delete_by_user_id(user_id)
        delete_wechat_user_by_user_id(user_id)
        delete_assign_person_by_user_id(user_id)
        logger.info('uuid: %s' % self.uuid)
        logger.error('Unexpected sync check result: %s' % r.text)
        return None
    return pm.group(2)


def get_msg(self):
    self.loginInfo['deviceid'] = 'e' + repr(random.random())[2:17]
    url = '%s/webwxsync?sid=%s&skey=%s&pass_ticket=%s' % (
        self.loginInfo['url'], self.loginInfo['wxsid'],
        self.loginInfo['skey'], self.loginInfo['pass_ticket'])
    data = {
        'BaseRequest': self.loginInfo['BaseRequest'],
        'SyncKey': self.loginInfo['SyncKey'],
        'rr': ~int(time.time()), }
    headers = {
        'ContentType': 'application/json; charset=UTF-8',
        'User-Agent': config.USER_AGENT}
    r = self.s.post(url, data=json.dumps(data),
                    headers=headers, timeout=config.TIMEOUT)
    dic = json.loads(r.content.decode('utf-8', 'replace'))
    if dic['BaseResponse']['Ret'] != 0:
        return None, None
    self.loginInfo['SyncKey'] = dic['SyncKey']
    self.loginInfo['synckey'] = '|'.join(['%s_%s' % (item['Key'], item['Val'])
                                          for item in dic['SyncCheckKey']['List']])
    return dic['AddMsgList'], dic['ModContactList']


def logout(self):
    if self.alive:
        url = '%s/webwxlogout' % self.loginInfo['url']
        params = {
            'redirect': 1,
            'type': 1,
            'skey': self.loginInfo['skey'], }
        headers = {'User-Agent': config.USER_AGENT}
        self.s.get(url, params=params, headers=headers)
        self.alive = False
    self.isLogging = False
    self.s.cookies.clear()
    del self.chatroomList[:]
    del self.memberList[:]
    del self.mpList[:]
    return ReturnValue({'BaseResponse': {
        'ErrMsg': 'logout successfully.',
        'Ret': 0, }})
